package com.bzkj.document.service.whstransbill.impl;

import com.alibaba.fastjson2.JSONObject;
import com.bzkj.common.annotation.DataWarehouseScope;
import com.bzkj.common.constant.BillStatusConstant;
import com.bzkj.common.core.domain.AjaxResult;
import com.bzkj.common.core.domain.model.LoginUser;
import com.bzkj.common.core.page.TableDataInfo;
import com.bzkj.common.domain.NccApiResponse;
import com.bzkj.common.domain.NccRequestDTO;
import com.bzkj.common.enums.BusinessType;
import com.bzkj.common.enums.DocumentType;
import com.bzkj.common.utils.DataProcessCommonUtils;
import com.bzkj.common.utils.MessageUtil;
import com.bzkj.common.utils.SecurityUtils;
import com.bzkj.common.utils.http.NccHttpUtils;
import com.bzkj.document.domain.BaseInfoMap;
import com.bzkj.document.domain.DocConfirmDTO;
import com.bzkj.document.domain.whstransbill.dto.WhsTransBillBodyDTO;
import com.bzkj.document.domain.whstransbill.dto.WhsTransBillHeaderDTO;
import com.bzkj.document.domain.whstransbill.dto.WhsTransBillRequestBody;
import com.bzkj.document.domain.whstransbill.dto.WhsTransQueryDTO;
import com.bzkj.document.domain.whstransbill.vo.WhsTransBillBodyVo;
import com.bzkj.document.domain.whstransbill.vo.WhsTransBillHeaderVo;
import com.bzkj.document.enums.InventoryCheck;
import com.bzkj.document.exception.InventoryException;
import com.bzkj.document.mapper.WhstransbillMapper;
import com.bzkj.document.mapper.WmsWareHouseInventoryMapper;
import com.bzkj.document.service.whstransbill.WhstransbillService;
import com.bzkj.document.utils.common.DataProcessUtils;
import com.bzkj.document.utils.common.DocumentNoUtils;
import com.bzkj.document.utils.common.InventoryManagerUtils;
import com.bzkj.document.utils.transferorder.TransferOrderUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @projectName: prt-wms
 * @package: com.bzkj.document.service.whstransbill.impl
 * @className: WhstransbillServiceImpl
 * @description: 转库出库服务层
 * @author: C1309
 * @createDate: 2024年12月11日
 * @version: v1.0
 */
@Service
public class WhstransbillServiceImpl implements WhstransbillService {

    @Resource
    private WhstransbillMapper whstransbillMapper;

    /**
     * 固定的 pk_org 值
     */
    private static final String PK_ORG = "111";

    /**
     * NCC接口请求工具
     */
    @Resource
    private NccHttpUtils nccHttpUtils;

    /**
     * WMS单据编号生成工具
     */
    @Resource
    private DocumentNoUtils documentNoUtils;

    /**
     * 消息提醒
     */
    @Resource
    private MessageUtil messageUtil;

    /**
     * 库存管理工具类
     */
    @Resource
    private InventoryManagerUtils inventoryManagerUtils;

    /**
     * 转库出库单工具类
     */
    @Resource
    private TransferOrderUtils transferOrderUtils;

    @Resource
    private WmsWareHouseInventoryMapper wmsWareHouseInventoryMapper;
    /**
     * NCC查询接口地址
     */
    private static final String QUERY_API_URL = "/nccloud/api/ic/whstrans/query";

    /**
     * NCC新增接口地址
     */
    private static final String ADD_API_URL = "/nccloud/api/ic/whstrans/save";

    /**
     * NCC更新接口地址
     */
    private static final String UPDATE_API_URL = "/nccloud/api/ic/whstrans/update";

    /**
     * NCC签字接口地址
     */
    private static final String SIGN_API_URL = "/nccloud/api/ic/whstrans/commit";


    // ==========================================================
    // 模块名称: 材料出库单NCC查询模块
    // 功能描述: 对NCC材料出库单进行查询操作
    // ==========================================================

    /**
     * 查询转库出库单据
     *
     * @param nccRequestDTO 查询条件
     * @return 查询结果
     */
    @Override
    public TableDataInfo selectNccTransferOrders(NccRequestDTO nccRequestDTO) {
        try {
            // 发起请求并处理响应
            transferOrderUtils.setWarehouseIds(nccRequestDTO);
            NccApiResponse nccApiResponse = nccHttpUtils.post(QUERY_API_URL, JSONObject.toJSONString(nccRequestDTO));

            // 校验响应数据
            DataProcessCommonUtils.validateNccResponse(nccApiResponse);

            // 解析NCC返回的转库单数据
            List<Map<String, Object>> dataList = transferOrderUtils.processTransferOrderResponse(nccApiResponse, true);

//            if (dataList == null || dataList.isEmpty()) {
//                throw new RuntimeException("Oops~ 当前条件下没有找到单据，试试调整查询条件吧！");
//            }

            List<Map<String, Object>> list = extractTransferOrders(nccRequestDTO.getTansType() == null ? null : nccRequestDTO.getTansType(), dataList);

//            if (list.isEmpty()) {
//                throw new RuntimeException("Oops~ 当前条件下没有找到单据，试试调整查询条件吧！");
//            }

            // 返回分页数据
            return DataProcessUtils.startPageInfo(nccRequestDTO.getPageNum(), nccRequestDTO.getPageSize(), list);
        } catch (Exception e) {
            // 捕获请求异常并返回具体错误提示
            String errorMessage = messageUtil.operateExceptionMessage(DocumentType.TRANSFER_ORDER.getCode(), e, "查询");
            throw new RuntimeException(errorMessage, e);
        }
    }

    /**
     * 提取对应类型的转库单数据
     * TransferWareHouseIn: 转库入库单
     * TransferWareHouseOut: 转库出库单
     * TransferWareHouseMove: 移库单
     */
    private List<Map<String, Object>> extractTransferOrders(String billType, List<Map<String, Object>> dataList) {
        // WMS管理的仓库ID集合
        Set<String> warehouseIds = wmsWareHouseInventoryMapper.selectWarehouseId();
        // 安全获取仓库权限集合
        Set<String> warehouses = Optional.ofNullable(SecurityUtils.getLoginUser())
                .map(LoginUser::getWarehouses)
                .orElse(Collections.emptySet());

        // 快速返回场景：无过滤条件或拥有全部权限
        if (billType == null) {
            return new ArrayList<>(dataList);
        }

        // 使用Stream处理数据过滤
        return dataList.stream()
                .filter(data -> isBillTypeMatch(data, billType))
                .filter(data -> hasWarehousePermission(data, billType, warehouses, warehouseIds))
                .collect(Collectors.toList());
    }

    /**
     * 校验单据类型是否匹配
     */
    private boolean isBillTypeMatch(Map<String, Object> data, String expectedType) {
        return Optional.ofNullable((Map<String, Object>) data.get("header"))
                .map(header -> (String) header.get("transType"))
                .filter(transType -> transType.equals(expectedType))
                .isPresent();
    }

    /**
     * 仓库权限校验
     *
     * @param billType        单据类型
     * @param warehouses      用户仓库权限集合
     * @param wmsWarehouseIds WMS仓库ID集合
     * @param data            单据数据
     * @return true/false
     */
    private boolean hasWarehousePermission(Map<String, Object> data, String billType, Set<String> warehouses, Set<String> wmsWarehouseIds) {
        try {

            // 移库单无需校验仓库
            if ("TransferWareHouseMove".equals(billType)) {
                return true;
            }

            // 获取目标仓库字段名
            String warehouseField = getWarehouseField(billType);

            // 提取仓库编码
            String warehouseCode = extractWarehouseCode(data, warehouseField);

            // 如果是管理员则判断仓库是否为WMS管理的仓库
            if (warehouses.contains("*")) {
                return wmsWarehouseIds.contains(warehouseCode);
            }
            // 如果是普通用户则判断仓库是否为WMS管理的仓库且在权限范围内
            Set<String> filterWareHouses = warehouses.stream()
                    .filter(wmsWarehouseIds::contains)
                    .collect(Collectors.toSet());

            // 校验权限
            return filterWareHouses.contains(warehouseCode);
        } catch (Exception e) {
//            log.error("仓库权限校验失败，单据类型：{}，数据：{}", billType, data, e);
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 根据单据类型获取仓库字段名
     */
    private String getWarehouseField(String billType) {
        switch (billType) {
            case "TransferWareHouseIn":
                return "cotherwhid";
            case "TransferWareHouseOut":
                return "cwarehouseid";
            default:
                throw new IllegalArgumentException("不支持的单据类型: " + billType);
        }
    }

    /**
     * 统一仓库编码提取逻辑
     */
    private String extractWarehouseCode(Map<String, Object> data, String fieldName) {
        // 获取仓库信息Map
        Map<String, Object> warehouseMap = Optional.ofNullable((Map<String, Object>) data.get("header")).map(
                header -> (Map<String, Object>) header.get(fieldName)
        ).orElseThrow(() -> new RuntimeException("仓库信息缺失，字段: " + fieldName));

        // 智能获取编码（优先取code，否则取value）
        Object codeValue = Optional.ofNullable(warehouseMap.get("isMap"))
                .filter(isMap -> Boolean.TRUE.equals(isMap))
                .map(isMap -> warehouseMap.get("code"))
                .orElse(warehouseMap.get("value"));

        return Optional.ofNullable(codeValue)
                .map(Object::toString)
                .map(String::trim)
                .filter(s -> !s.isEmpty())
                .orElseThrow(() -> new RuntimeException("无效的仓库编码格式"));
    }


    // ==========================================================
    // 模块名称: NCC转库单WMS确认模块
    // 功能描述: WMS对NCC转库单进行确认操作
    // ==========================================================

    /**
     * 确认转库出库单据
     *
     * @param docConfirmDTO 确认数据
     * @return 确认结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult confirmNccTransBill(DocConfirmDTO docConfirmDTO) {
        // 提取登录用户信息
        LoginUser loginUser = docConfirmDTO.getLoginUser();

        // 提取单据日期范围信息
        String billDate = nccHttpUtils.getBillDate(docConfirmDTO.getBillDate());

        // 提取单据号信息
        List<String> vBillCodeList = docConfirmDTO.getvBillCodeList();

        // 构建处理成功的单据列表
        List<String> successList = new ArrayList<>();

        for (String vBillCode : vBillCodeList) {
            if (isBillExist(vBillCode)) {
                continue;
            }
            try {
                // 调用 NCC 接口获取转库单数据
                List<Map<String, Object>> transboundOrders = fetchTransboundOrders(vBillCode, billDate);

                // 处理转库单
                String errorMsg = processTransboundOrders(transboundOrders, loginUser, successList, vBillCode);
                if (errorMsg != null) {
                    throw new RuntimeException(errorMsg);
                }
            } catch (Exception e) {
                handleException(e, DocumentType.TRANSFER_ORDER.getCode());
            }
        }
        return AjaxResult.success(messageUtil.operateSuccessMessage(successList, DocumentType.TRANSFER_ORDER.getCode(), "确认"));
    }

    /**
     * 检查单据是否已存在
     */
    private boolean isBillExist(String billCode) {
        return whstransbillMapper.selectIsExist(billCode) > 0;
    }

    /**
     * 调用 NCC 接口获取物料出库单数据
     */
    private List<Map<String, Object>> fetchTransboundOrders(String billCode, String billDate) throws Exception {
        // 向NCC发起请求
        String confirmQuery = nccHttpUtils.getConfirmQuery(billDate, billCode);
        NccApiResponse nccApiResponse = nccHttpUtils.post(QUERY_API_URL, confirmQuery);
        // 校验 NCC 返回结果
        DataProcessCommonUtils.validateNccResponse(nccApiResponse);
        // 解析返回结果
        return transferOrderUtils.processTransferOrderResponse(nccApiResponse, true);
    }

    /**
     * 处理转库单数据
     */
    @Transactional(rollbackFor = Exception.class)
    public String processTransboundOrders(List<Map<String, Object>> transboundOrders, LoginUser loginUser,
                                          List<String> successList, String billCode) {
        for (Map<String, Object> transboundOrder : transboundOrders) {
            Map<String, Object> headerMap = extractHeaderMap(transboundOrder, loginUser);
            List<Map<String, Object>> detailsList = extractDetailsList(transboundOrder, loginUser);

            String transType = headerMap.get("transType").toString();
            // 0表示确认
            inventoryManagerUtils.wmsSkuRulesUnitTansBill(detailsList, transType, 0);

            String cwarehouseid;
            if (transType.equals("TransferWareHouseOut") || transType.equals("TransferWareHouseMove")) {
                cwarehouseid = headerMap.get("cwarehouseid") == null ? "" : inventoryManagerUtils.getPkFromTargetMap((HashMap<String, Object>) headerMap.get("cwarehouseid"));
            } else {
                cwarehouseid = headerMap.get("cotherwhid") == null ? "" : inventoryManagerUtils.getPkFromTargetMap((HashMap<String, Object>) headerMap.get("cotherwhid"));
            }

            int detailsResult = batchInsertDetails(detailsList, headerMap.get("transType").toString(),
                    headerMap.get("vtrantypecode").toString(), cwarehouseid);

            billCode = billCode == null ? "" : headerMap.get("vbillcode").toString();

            if (detailsResult == detailsList.size()) {
                // 插入表头数据
                int headerResult = whstransbillMapper.addWhstransOrderHeader(headerMap);
                if (headerResult > 0) {
                    try {
                        NccApiResponse nccApiResponse = nccHttpUtils.postMoveConfirm(UPDATE_API_URL, headerMap.get("cspecialhid").toString(), "Y");
                        if (nccApiResponse.isSuccess()) {
                            successList.add(billCode);
                        } else {
                            throw new RuntimeException("向NCC返回单据同步状态失败，请检查后重试！");
                        }
                    } catch (IOException e) {
                        throw new RuntimeException("向NCC返回单据同步状态失败，请检查后重试！");
                    }
                }
            }
        }
        return null;
    }

    /**
     * 提取并处理表头数据
     */
    private Map<String, Object> extractHeaderMap(Map<String, Object> materialOutboundOrder, LoginUser loginUser) {
        @SuppressWarnings("unchecked")
        Map<String, Object> headerMap = (Map<String, Object>) materialOutboundOrder.get("header");
        String wmsNo = documentNoUtils.generateTrfOrderNumber();
        headerMap.put("vdef49", wmsNo);
        headerMap.put("vdef50", wmsNo);
        DataProcessUtils.addHeaderInfo(headerMap, loginUser);
        return headerMap;
    }

    /**
     * 提取并处理明细数据
     */
    private List<Map<String, Object>> extractDetailsList(Map<String, Object> transboundOrder, LoginUser loginUser) {
        @SuppressWarnings("unchecked")
        List<Map<String, Object>> detailsList = (List<Map<String, Object>>) transboundOrder.get("details");
        for (Map<String, Object> detailMap : detailsList) {
            DataProcessUtils.addDetailInfo(detailMap, loginUser);
        }
        return detailsList;
    }

    /**
     * 批量插入明细数据
     */
    private int batchInsertDetails(List<Map<String, Object>> detailsList, String tansType, String vtrantypecode, String cwarehouseidPk) {
        int count = 0;
        for (Map<String, Object> detail : detailsList) {
            if (tansType.equals("TransferWareHouseOut") || tansType.equals("TransferWareHouseMove")) {
                @SuppressWarnings("unchecked")
                Map<String, Object> cmaterialvid = (Map<String, Object>) detail.get("cmaterialvid");
                String pkMaterial;
                if ((boolean) cmaterialvid.get("isMap")) {
                    pkMaterial = cmaterialvid.get("pk").toString();
                } else {
                    pkMaterial = cmaterialvid.get("value").toString();
                }
                //批号
                String vbatchcode = detail.get("vbatchcode") == null ? "" : detail.get("vbatchcode").toString();

                // 单据中应发数量
                Object nshouldnumObj = detail.get("nnum");
                double nshouldnum = 0;
                if (nshouldnumObj != null) {
                    nshouldnum = Double.parseDouble(nshouldnumObj.toString());
                }
                // 单据中的请领数量
                Object vbdef1 = detail.get("vbdef1");
                double vbdef1Num = 0;
                if (vbdef1 != null) {
                    vbdef1Num = Double.parseDouble(vbdef1.toString());
                }
                double queryNum = Math.max(vbdef1Num, nshouldnum);
                String cstateid = detail.get("cstateid") == null ? "" : detail.get("cstateid").toString();
                String cproductorid = detail.get("cproductorid") == null ? "" : inventoryManagerUtils.getPkFromTargetMap((HashMap<String, Object>) detail.get("cproductorid"));

                int resultType = inventoryManagerUtils.isEnough("", vtrantypecode, pkMaterial, vbatchcode, queryNum, "1", cstateid, cproductorid, cwarehouseidPk);
                if (resultType == InventoryCheck.ENOUGH.ordinal() || nshouldnum < 0) {
                    count += whstransbillMapper.addWhstransOrderDetails(detail);
                } else if (resultType == InventoryCheck.NO_ENOUGH.ordinal()) {
                    throw new RuntimeException("行号：" + detail.get("crowno") + "-->" + cmaterialvid.get("name") + "库存可用量不足！");
                } else if (resultType == InventoryCheck.NOT_ALLOWED.ordinal()) {
                    throw new RuntimeException("行号：" + detail.get("crowno") + "-->" + cmaterialvid.get("name") + "当前商品不支持在此单据类型下使用！");
                }
            } else {
                count += whstransbillMapper.addWhstransOrderDetails(detail);
            }
        }
        return count;
    }

    /**
     * 异常处理
     */
    private void handleException(Exception e, String documentType) {
        String exceptionMessage = messageUtil.operateExceptionMessage(documentType, e, "确认");
        throw new RuntimeException(exceptionMessage, e);
    }


    // ==========================================================
    // 模块名称: 新增NCC转库单模块
    // 功能描述: WMS新增NCC转库单操作
    // ==========================================================

    /**
     * 新增转库单
     *
     * @param whsTransBillRequestBody 单据数据
     * @return 操作结果
     */

    @Transactional(rollbackFor = Exception.class)
    @Override
    public AjaxResult addTransferOrders(WhsTransBillRequestBody whsTransBillRequestBody) {
        // 初始化成功处理列表
        List<String> successList = new ArrayList<>();
        // 提取登录用户信息
        LoginUser loginUser = whsTransBillRequestBody.getLoginUser();
        // 提取请求参数头信息
        WhsTransBillHeaderDTO whsTransBillHeaderVo = whsTransBillRequestBody.getWhsTransBillHeaderVo();
        // 提取请求参数明细信息
        List<WhsTransBillBodyDTO> whsTransBillBodyList = whsTransBillRequestBody.getWhsTransBillBodyList();

        // 检查头信息是否为空
        if (whsTransBillHeaderVo == null) {
            return AjaxResult.warn("小提示：转库单据头信息缺失，请确认提交的请求格式是否正确！");
        }

        // 检查明细信息是否为空或列表为空
        if (whsTransBillBodyList == null || whsTransBillBodyList.isEmpty()) {
            return AjaxResult.warn("注意：未提供任何转库单明细信息");
        }

        // 将请求对象转为 JSON
        String jsonString = JSONObject.toJSONString(whsTransBillRequestBody);
        try {
            // 调用 NCC 接口
            NccApiResponse nccApiResponse = nccHttpUtils.post(ADD_API_URL, "[" + jsonString + "]");

            // 校验NCC返回的数据
            DataProcessCommonUtils.validateNccResponse(nccApiResponse);

            // 解析返回数据
            List<Map<String, Object>> transferOrders = transferOrderUtils.processTransferOrderResponse(nccApiResponse, true);

            // 处理转库单
            processTransOrders(transferOrders, loginUser, successList, null);

        } catch (Exception e) {
            // 统一异常处理并抛出运行时异常
            String exceptionMessage = messageUtil.operateExceptionMessage(
                    DocumentType.TRANSFER_ORDER.getCode(), e, "新增"
            );
            throw new RuntimeException(exceptionMessage, e);
        }
        // 返回操作成功结果
        return AjaxResult.success(
                messageUtil.operateSuccessMessage(successList, DocumentType.TRANSFER_ORDER.getCode(), "新增")
        );
    }

    /**
     * 处理转库单数据
     */
    @Transactional(rollbackFor = Exception.class)
    public void processTransOrders(List<Map<String, Object>> transOrders, LoginUser loginUser, List<String> successList, String billCode) {
        for (Map<String, Object> transOrder : transOrders) {
            Map<String, Object> headerMap = extractHeaderMap(transOrder, loginUser);
            // 插入表头数据
            int headerResult = whstransbillMapper.addWhstransOrderHeader(headerMap);
            if (billCode == null) {
                billCode = (String) headerMap.get("vbillcode");
            }

            String transType = headerMap.get("transType").toString();

            String cwarehouseid;
            if (transType.equals("TransferWareHouseOut") || transType.equals("TransferWareHouseMove")) {
                cwarehouseid = headerMap.get("cwarehouseid") == null ? "" : inventoryManagerUtils.getPkFromTargetMap((HashMap<String, Object>) headerMap.get("cwarehouseid"));
            } else {
                cwarehouseid = headerMap.get("cotherwhid") == null ? "" : inventoryManagerUtils.getPkFromTargetMap((HashMap<String, Object>) headerMap.get("cotherwhid"));
            }

            if (headerResult > 0) {
                List<Map<String, Object>> detailsList = extractDetailsList(transOrder, loginUser);
                // 0表示新增
                inventoryManagerUtils.wmsSkuRulesUnitTansBill(detailsList, headerMap.get("transType").toString(), 0);
                int detailsResult = batchInsertDetails(detailsList, (String) headerMap.get("transType"), headerMap.get("vtrantypecode").toString(), cwarehouseid);

                if (detailsResult == detailsList.size()) {
                    successList.add(billCode);
                }
            }
        }
    }

    // ==========================================================
    // 模块名称: 查询已经确认转库单模块
    // 功能描述: 查询转库单操作
    // ==========================================================

    /**
     * 本地查询转库出库单据
     *
     * @param whsTransQueryDTO 查询条件
     * @param pageNum          当前页
     * @param pageSize         每页条数
     * @return 查询结果
     */
    @Override
    @DataWarehouseScope(deptAlias = "d", userAlias = "u")
    public TableDataInfo selectLocalTransferOrders(WhsTransQueryDTO whsTransQueryDTO, int pageNum, int pageSize) {
        ArrayList<HashMap<String, Object>> responseList = new ArrayList<>();
        // 处理日期范围过滤条件
        DataProcessUtils.handleDateRange(whsTransQueryDTO);
        // 查询表头数据
        List<WhsTransBillHeaderVo> whsTransBillHeaderVos = whstransbillMapper.selectLocalWhstHeader(whsTransQueryDTO);
        // 优化过滤条件：提前检查是否存在需要过滤的物料
        String filterMaterialOid = whsTransQueryDTO.getMaterial() != null ? whsTransQueryDTO.getMaterial() : "";
        // 遍历表头数据，逐个查询对应明细
        for (WhsTransBillHeaderVo whsTransBillHeaderVo : whsTransBillHeaderVos) {
            String cspecialhid = whsTransBillHeaderVo.getCspecialhid();
            // 查询对应单据明细
            List<WhsTransBillBodyVo> whsTransBillBodyVos = whstransbillMapper.selectLocalWhstDetail(cspecialhid, whsTransBillHeaderVo.getBillsState());
            if (whsTransBillBodyVos == null || whsTransBillBodyVos.isEmpty()) {
                continue;
            }
            // 如果存在物料过滤条件，先检查明细中是否包含该物料
            if (!filterMaterialOid.isEmpty()) {
                boolean containsMaterialCode = whsTransBillBodyVos.stream()
                        .anyMatch(body -> filterMaterialOid.equals(body.getCmaterialoid().getPk()));

                if (!containsMaterialCode) {
                    continue;  // 如果明细中不包含该物料，跳过当前表头
                }
            }
            // 创建结果映射
            HashMap<String, Object> whsTransMap = new HashMap<>(2);
            whsTransMap.put("header", whsTransBillHeaderVo);
            whsTransMap.put("details", whsTransBillBodyVos);
            // 将结果添加到结果列表
            responseList.add(whsTransMap);
        }
//        if (responseList.isEmpty()) {
//            throw new RuntimeException("Oops~ 当前条件下没有找到单据，试试调整查询条件吧！");
//        }
        return DataProcessCommonUtils.getTableInfo(responseList, pageNum, pageSize);
    }


    // ==========================================================
    // 模块名称: 修改NCC转库单模块
    // 功能描述: 修改转库单操作
    // ==========================================================

    /**
     * 修改转库出库单据
     *
     * @param responseBody 修改数据
     * @param loginUser    登录用户
     * @param isSign       是否跳过修改校验
     * @return 修改结果
     */
    @Override
    public AjaxResult updateWhsTransBoundOrder(HashMap<String, Object> responseBody, LoginUser loginUser, boolean isSign) {
        String vbillcode;

        try {
            // 提取并校验头信息
            HashMap<String, Object> headerMap = extractHeaderInfo(responseBody);
            String cspecialhid = headerMap.get("cspecialhid").toString();

            // 校验单据状态
            if (!isSign) {
                AjaxResult validationResult = validateBillStatus(cspecialhid);
                if (!validationResult.isSuccess()) {
                    return validationResult;
                }
            }
            // 封装 NCC 请求参数
            HashMap<String, Object> nccRequestMap = prepareNccRequest(responseBody);
            // 调用 NCC 接口并校验返回结果
            NccApiResponse nccApiResponse = nccHttpUtils.post(UPDATE_API_URL, JSONObject.toJSONString(nccRequestMap));
            DataProcessCommonUtils.validateNccResponse(nccApiResponse);

            //解析处理返回数据
            List<Map<String, Object>> list = transferOrderUtils.processTransferOrderResponse(nccApiResponse, false);

            vbillcode = processTranOrdersUpdate(list, loginUser);

        } catch (Exception e) {
            String exceptionMessage;
            if (!isSign) {
                exceptionMessage = messageUtil.operateExceptionMessage(
                        DocumentType.TRANSFER_ORDER.getCode(), e, "修改"
                );
            } else {
                return AjaxResult.error(messageUtil.operateExceptionMessage(
                        DocumentType.TRANSFER_ORDER.getCode(), e, "签字"
                ));
            }
            throw new RuntimeException(exceptionMessage, e);
        }
        return AjaxResult.success(
                messageUtil.operateSuccessMessage(
                        Collections.singletonList(vbillcode),
                        DocumentType.TRANSFER_ORDER.getCode(),
                        "修改"
                )
        );
    }

    /**
     * 提取头信息并校验
     */
    private HashMap<String, Object> extractHeaderInfo(HashMap<String, Object> responseBody) {
        @SuppressWarnings("unchecked")
        HashMap<String, Object> headerMap = (HashMap<String, Object>) responseBody.get("ic_whstrans_h");
        if (headerMap == null || !headerMap.containsKey("cspecialhid")) {
            throw new IllegalArgumentException("提示：单据头信息缺失或不完整！");
        }
        return headerMap;
    }

    /**
     * 校验单据状态
     */
    private AjaxResult validateBillStatus(String cspecialhid) {
        HashMap<String, String> billInfoMap = whstransbillMapper.getBillStatus(cspecialhid);
        String billState = billInfoMap.get("billState");
        return messageUtil.updateBillMessage(billState, DocumentType.MATERIAL_OUTBOUND.getDescription());
    }

    /**
     * 封装 NCC 请求参数
     */
    private HashMap<String, Object> prepareNccRequest(HashMap<String, Object> responseBody) {
        HashMap<String, Object> nccRequestMap = new HashMap<>(2);
        nccRequestMap.put("ic_whstrans_h", responseBody.get("ic_whstrans_h"));
        nccRequestMap.put("ic_whstrans_b", responseBody.get("ic_whstrans_b"));
        return nccRequestMap;
    }

    /**
     * 处理材料出库单
     */
    private String processTranOrdersUpdate(List<Map<String, Object>> tranOrderbounds, LoginUser loginUser) {
        String vbillcode = "";
        for (Map<String, Object> tranOrderbound : tranOrderbounds) {
            @SuppressWarnings("unchecked")
            Map<String, Object> headerInfoMap = (Map<String, Object>) tranOrderbound.get("header");
            vbillcode = headerInfoMap.get("vbillcode").toString();
            DataProcessUtils.updateInfo(headerInfoMap, loginUser);

            // 修改表头数据
            int resultNum = whstransbillMapper.updateWhsTransBoundOrder(headerInfoMap);
            if (resultNum <= 0) {
                throw new RuntimeException("wms中表头数据更新失败！");
            }

            // 修改表体数据
            @SuppressWarnings("unchecked")
            List<HashMap<String, Object>> detailsList =
                    (List<HashMap<String, Object>>) tranOrderbound.get("details");
            int count = updateOrderDetails(detailsList, loginUser);
            if (count != detailsList.size()) {
                String failureMessage = messageUtil.documentFailureMessage(
                        Collections.singletonList(headerInfoMap.get("vbillcode").toString()),
                        DocumentType.TRANSFER_ORDER.getCode(),
                        "修改",
                        "明细"
                );
                throw new RuntimeException(failureMessage);
            }
        }
        return vbillcode;
    }

    /**
     * 更新表体数据
     */
    private int updateOrderDetails(List<HashMap<String, Object>> detailsList, LoginUser loginUser) {
        int count = 0;
        for (HashMap<String, Object> detailMap : detailsList) {
            DataProcessUtils.updateInfo(detailMap, loginUser);
            count += whstransbillMapper.updateWhsTransBoundOrderDetails(detailMap);
        }
        return count;
    }


    // ==========================================================
    // 模块名称: NCC转库单签字模块
    // 功能描述: 转库单签字操作
    // ==========================================================

    /**
     * NCC转库单签字
     *
     * @param vbillcode 单据头
     * @param loginUser 登录用户
     * @return 操作结果
     */
    @Override
    public AjaxResult signatureWhsTransOutBound(String vbillcode, LoginUser loginUser) {
        // 参数校验：请求参数是否为空，headerId是否存在
        if (vbillcode == null || vbillcode.isEmpty()) {
            return AjaxResult.error(messageUtil.noSelectOrderMessage(DocumentType.TRANSFER_ORDER.getCode(), "签字"));
        }
        // 获取当前单据状态
        HashMap<String, String> billStatusMap = whstransbillMapper.getBillStatus(vbillcode);

        String billStatus = billStatusMap.get("billState");
        String billCode = billStatusMap.get("vbillcode");
        String cspecialhid = billStatusMap.get("cspecialhid");
        // 根据单据状态返回消息
        AjaxResult ajaxResult = messageUtil.signedBillMessage(billStatus, DocumentType.TRANSFER_ORDER.getDescription());
        return ajaxResult.isSuccess() ? processSignBill(cspecialhid, billCode, loginUser) : ajaxResult;
    }


    /**
     * 对已完成的单据进行签字处理
     */
    private AjaxResult processSignBill(String cspecialhid, String vbillcode, LoginUser loginUser) {
        try {
            // 准备表头数据
            HashMap<String, Object> headerAndTypeMap = prepareHeaderData(cspecialhid);

            String transType = headerAndTypeMap.get("transType").toString();
            String vtrantypecode = headerAndTypeMap.get("vtrantypecode").toString();

            String cwarehouseid;
            if ("TransferWareHouseOut".equals(transType) || "TransferWareHouseMove".equals(transType)) {
                cwarehouseid = headerAndTypeMap.get("cwarehouseid") == null ? "" : ((BaseInfoMap) headerAndTypeMap.get("cwarehouseid")).getPk();
            } else {
                cwarehouseid = headerAndTypeMap.get("cotherwhid") == null ? "" : ((BaseInfoMap) headerAndTypeMap.get("cotherwhid")).getPk();
            }
            // 校验并准备明细数据
            List<HashMap<String, Object>> detailList = prepareDetails(cspecialhid, vbillcode, transType, vtrantypecode, cwarehouseid);
            if (detailList == null) {
                return AjaxResult.error(messageUtil.updateDocumentZeroQuantityMessage(DocumentType.TRANSFER_ORDER.getCode()));
            }

            // 准备表头数据
            HashMap<String, Object> headerMap = new HashMap<>();
            headerMap.put("cspecialhid", cspecialhid);
            // 判断是否为调拨单,并对非移库单进行更新操作
//            if (!transType.equals("TransferWareHouseMove")) {
            // 更新转库单
            AjaxResult updateResult = updateTransOrder(headerMap, detailList, loginUser);
            if (!updateResult.isSuccess()) {
                return updateResult;
            }
//            }

            // 调用外部接口并更新状态
            return handleExternalApiAndInventory(vbillcode, cspecialhid, loginUser, detailList.size(), transType);

        } catch (Exception e) {
            // 捕获异常并包装为运行时异常
            // logError(e); // 记录日志
            throw new RuntimeException("小提示：转库出库单据签字时遇到了一点小问题，具体原因：" + e.getMessage() + "。别急，检查一下再试一次吧！如果有持续的问题，记得联系技术支持哦～", e);
        }
    }

    /**
     * 校验并准备明细数据
     *
     * @param cspecialhid 单据表头主键
     * @return 明细列表或null（校验失败）
     */
    private List<HashMap<String, Object>> prepareDetails(String cspecialhid, String vBillCode, String transType, String vtrantypecode, String cwarehouseid) {
        List<HashMap<String, Object>> detailList = new ArrayList<>();
        List<WhsTransBillBodyVo> details = whstransbillMapper.selectLocalWhstDetail(cspecialhid, null);

        for (WhsTransBillBodyVo detail : details) {
            if (detail.getNnum() == 0) {
                return null;
            }
            // 库存校验
            if ("TransferWareHouseOut".equals(transType) || "TransferWareHouseMove".equals(transType)) {
                String cstateid = detail.getCstateid() == null ? "" : detail.getCstateid();
                String cproductorid = detail.getCproductorid() == null ? "" : detail.getCproductorid().getPk();

                int resultType = inventoryManagerUtils.isEnough(
                        vBillCode,
                        vtrantypecode,
                        detail.getCmaterialvid().getPk(),
                        detail.getVbatchcode(),
                        detail.getNnum(),
                        "2",
                        cstateid,
                        cproductorid,
                        cwarehouseid);

                if (resultType == InventoryCheck.NO_ENOUGH.ordinal()) {
                    throw new RuntimeException(detail.getCmaterialvid().getName() + "库存可用量不足！");
                }
                if (resultType == InventoryCheck.NOT_ALLOWED.ordinal()) {
                    throw new RuntimeException(detail.getCmaterialvid().getName() + "当前商品不支持在此单据类型下使用！");
                }
            }

            HashMap<String, Object> detailMap = new HashMap<>();
            detailMap.put("cspecialbid", detail.getCspecialbid());
            detailMap.put("nnum", detail.getNnum());
            detailList.add(detailMap);
        }
        return detailList;
    }

    /**
     * 准备表头数据
     *
     * @param cspecialhid 单据编号
     * @return 表头数据
     */
    private HashMap<String, Object> prepareHeaderData(String cspecialhid) {

        WhsTransBillHeaderVo whsTransBillHeaderVo = whstransbillMapper.selectTransboundOrderHeaderByBillCode(cspecialhid);
        if (whsTransBillHeaderVo == null) {
            throw new IllegalStateException("转库单表头信息不存在！");
        }

        HashMap<String, Object> headerMap = new HashMap<>();
        headerMap.put("cspecialhid", whsTransBillHeaderVo.getCspecialhid());
        headerMap.put("transType", whsTransBillHeaderVo.getTransType());
        headerMap.put("vtrantypecode", whsTransBillHeaderVo.getVtrantypecode());
        headerMap.put("cwarehouseid", whsTransBillHeaderVo.getCwarehouseid());
        headerMap.put("cotherwhid", whsTransBillHeaderVo.getCotherwhid());
        return headerMap;
    }

    /**
     * 更新材料出库单
     *
     * @param headerMap  表头数据
     * @param detailList 明细列表
     * @param loginUser  登录用户
     * @return 更新结果
     */
    private AjaxResult updateTransOrder(HashMap<String, Object> headerMap, List<HashMap<String, Object>> detailList, LoginUser loginUser) {
        HashMap<String, Object> resultMap = new HashMap<>();
        resultMap.put("ic_whstrans_h", headerMap);
        resultMap.put("ic_whstrans_b", detailList);
        return updateWhsTransBoundOrder(resultMap, loginUser, true);
    }

    /**
     * 处理外部接口调用和库存更新
     *
     * @param cspecialhid 表头主键
     * @param loginUser   登录用户
     * @param detailSize  明细数量
     * @return 结果
     */
    private AjaxResult handleExternalApiAndInventory(String vbillcode, String cspecialhid, LoginUser loginUser, int detailSize, String transType) throws IOException {

        String json = "{vbillcode:\"" + vbillcode + "\"}";
        // 调用外部接口
        NccApiResponse apiResponse = nccHttpUtils.post(SIGN_API_URL, json);

        // 校验NCC响应
        DataProcessCommonUtils.validateNccResponse(apiResponse);

        whstransbillMapper.updateBillState(cspecialhid, BillStatusConstant.SIGNED_CODE, loginUser.getUsername(), DataProcessUtils.getLocalDate());
        // 更新库存管理cotherwhid_code
        int rowCount = 0;
        if (Objects.equals(transType, "TransferWareHouseIn")) {
            rowCount = inventoryManagerUtils.wmsWarehouseIn(vbillcode, "TransferWareHouseIn");
        } else if (Objects.equals(transType, "TransferWareHouseOut")) {
            rowCount = inventoryManagerUtils.wmsWarehouseOut(vbillcode, "TransferWareHouseOut");
        } else if (Objects.equals(transType, "TransferWareHouseMove")) {
            rowCount = inventoryManagerUtils.wmsWarehouseOut(vbillcode, "TransferWareHouseMove");
        }

        if (Objects.equals(transType, "TransferWareHouseMove")) {
            if (detailSize * 2 == rowCount) {
                // 更新单据状态
                return AjaxResult.success(messageUtil.operateSuccessMessage(Collections.singletonList(vbillcode), DocumentType.TRANSFER_ORDER.getCode(), "签字"));
            }
        } else {
            if (detailSize == rowCount) {
                // 更新单据状态
                return AjaxResult.success(messageUtil.operateSuccessMessage(Collections.singletonList(vbillcode), DocumentType.TRANSFER_ORDER.getCode(), "签字"));
            }
        }
        whstransbillMapper.updateBillState(cspecialhid, BillStatusConstant.WMS_FAILURE_CODE, loginUser.getUsername(), DataProcessUtils.getLocalDate());
        return AjaxResult.error(messageUtil.updateDocumentWmsFailureMessage(DocumentType.TRANSFER_ORDER.getCode()));
    }

    /**
     * 转库单撤回至未收货状态
     *
     * @param headerId  表头主键
     * @param loginUser 登录用户
     * @return 操作结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult orderBack(String headerId, LoginUser loginUser) {
        HashMap<String, String> billStatusMap = whstransbillMapper.getBillStatus(headerId);
        String billState = billStatusMap.get("billState");
        String vbillCode = billStatusMap.get("vbillcode");
        AjaxResult ajaxResult = messageUtil.cancelExtractBillMessage(billState, DocumentType.TRANSFER_ORDER.getDescription());
        return ajaxResult.isSuccess() ? processOrderBack(headerId, loginUser, vbillCode) : ajaxResult;
    }

    private AjaxResult processOrderBack(String headerId, LoginUser loginUser, String vbillCode) {
        // 撤回转库单表头
        int i = whstransbillMapper.orderBackHead(headerId, loginUser.getUserId().toString());
        if (i > 0) {
            // 撤回转库单表体
            int i1 = whstransbillMapper.orderBackDetails(headerId, loginUser.getUserId().toString());
            if (i1 > 0) {
                return AjaxResult.success(messageUtil.operateSuccessMessage(Collections.singletonList(vbillCode), DocumentType.TRANSFER_ORDER.getCode(), "取消提取"));
            }
        }
        return AjaxResult.error("系统出现未知错误，请联系系统管理员处理！");
    }

    /**
     * 更新库存
     *
     * @param cspecialhid 表头主键
     * @param loginUser   登录用户
     * @return 操作结果
     */
    @Override
    public AjaxResult updateInventory(String cspecialhid, LoginUser loginUser) {
        // 获取单据表头
        WhsTransBillHeaderVo whsTransBillHeaderVo = whstransbillMapper.selectTransboundOrderHeaderByBillCode(cspecialhid);
        // 获取明细信息
        List<WhsTransBillBodyVo> details = whstransbillMapper.selectLocalWhstDetail(cspecialhid, null);

        int rowCount = 0;
        try {
            if (Objects.equals(whsTransBillHeaderVo.getTransType(), "TransferWareHouseIn")) {
                // 执行入库
                rowCount = inventoryManagerUtils.wmsWarehouseIn(whsTransBillHeaderVo.getVbillcode(), "TransferWareHouseIn");
            } else if (Objects.equals(whsTransBillHeaderVo.getTransType(), "TransferWareHouseOut")) {
                // 转库出检查库存是否充足
                checkInventory(details, whsTransBillHeaderVo);
                // 执行出库
                rowCount = inventoryManagerUtils.wmsWarehouseOut(whsTransBillHeaderVo.getVbillcode(), "TransferWareHouseOut");
            }
            if (details.size() == rowCount || Objects.equals(whsTransBillHeaderVo.getTransType(), "TransferWareHouseMove")) {
                // 更新单据状态
                updateBillState(cspecialhid, BillStatusConstant.SIGNED_CODE, loginUser);
                return AjaxResult.success(messageUtil.operateSuccessMessage(Collections.singletonList(whsTransBillHeaderVo.getVbillcode()), DocumentType.TRANSFER_ORDER.getCode(), "签字"));
            } else {
                return AjaxResult.error(messageUtil.updateDocumentWmsFailureMessage(DocumentType.TRANSFER_ORDER.getCode()));
            }
        } catch (InventoryException e) {
//            log.error("库存检查失败，单据号：{}，错误信息：{}", whsTransBillHeaderVo.getVbillcode(), e.getMessage());
            return AjaxResult.error(e.getMessage());
        }
    }

    /**
     * 删除转库单
     *
     * @param cgeneralhid 表头主键
     * @param reason      删除原因
     * @param loginUser   登录用户
     * @return 操作结果
     */
    @Override
    public AjaxResult deleteTransferOrders(String cgeneralhid, String reason, LoginUser loginUser) {
        if (cgeneralhid == null) {
            return AjaxResult.error(messageUtil.noSelectOrderMessage(DocumentType.TRANSFER_ORDER.getCode(), BusinessType.INVALID.getDescription()));
        } else if (cgeneralhid.trim().isEmpty()) {
            return AjaxResult.error(messageUtil.noSelectOrderMessage(DocumentType.TRANSFER_ORDER.getCode(), BusinessType.INVALID.getDescription()));
        }
        // 获取当前单据状态
        HashMap<String, String> billStateMap = whstransbillMapper.getBillStatus(cgeneralhid);
        String billStatus = billStateMap.get("billState");
        String vbillcode = billStateMap.get("vbillcode");

        // 调用消息工具（根据不同的单据状态返回不同的消息）
        AjaxResult ajaxResult = messageUtil.deleteBillMessage(billStatus, DocumentType.TRANSFER_ORDER.getDescription());

        return ajaxResult.isSuccess() ? handleDeleteBill(cgeneralhid, vbillcode, loginUser, reason) : ajaxResult;
    }

    /**
     * 作废销售出库单
     *
     * @param cgeneralhid 表头主键
     * @param vbillcode   单据号
     * @param loginUser   登录用户
     * @param reason      作废原因
     * @return 操作结果
     */
    private AjaxResult handleDeleteBill(String cgeneralhid, String vbillcode, LoginUser loginUser, String reason) {
        try {
            // 调用删除接口
            NccApiResponse nccApiResponse = nccHttpUtils.postMoveConfirm(UPDATE_API_URL, cgeneralhid, "");
            // 校验NCC返回的数据
            DataProcessCommonUtils.validateNccResponse(nccApiResponse);
            whstransbillMapper.updateBillState(cgeneralhid, BillStatusConstant.DELETED_CODE, loginUser.getUsername(), reason);
            // 校验NCC响应
            return AjaxResult.success(messageUtil.operateSuccessMessage(Collections.singletonList(vbillcode), DocumentType.TRANSFER_ORDER.getCode(), BusinessType.INVALID.getDescription()));
        } catch (Exception e) {
            String errorMessage = messageUtil.operateExceptionMessage(DocumentType.TRANSFER_ORDER.getCode(), e, BusinessType.INVALID.getDescription());
            //            log.error("采购入库单修改异常: ", e);
            throw new RuntimeException(errorMessage, e);
        }
    }


    /**
     * 检查库存是否充足
     *
     * @param details              明细信息
     * @param whsTransBillHeaderVo 表头信息
     * @throws InventoryException 库存异常
     */
    private void checkInventory(List<WhsTransBillBodyVo> details, WhsTransBillHeaderVo whsTransBillHeaderVo) throws InventoryException {
        String transType = whsTransBillHeaderVo.getTransType();
        String cwarehouseid;
        if (Objects.equals(transType, "TransferWareHouseOut") || Objects.equals(transType, "TransferWareHouseMove")) {
            cwarehouseid = whsTransBillHeaderVo.getCwarehouseid() == null ? "" : whsTransBillHeaderVo.getCwarehouseid().getPk();
        } else {
            cwarehouseid = whsTransBillHeaderVo.getCotherwhid() == null ? "" : whsTransBillHeaderVo.getCotherwhid().getPk();
        }
        for (WhsTransBillBodyVo detail : details) {
            String cproductorid = detail.getCproductorid() == null ? "" : detail.getCproductorid().getPk();
            int resultType = inventoryManagerUtils.isEnough(
                    detail.getVbillcode(),
                    whsTransBillHeaderVo.getVtrantypecode(),
                    detail.getCmaterialvid().getPk(),
                    detail.getVbatchcode(),
                    detail.getNnum(),
                    "2",
                    detail.getCstateid(), cproductorid, cwarehouseid);
            if (resultType == InventoryCheck.NO_ENOUGH.ordinal()) {
                throw new InventoryException(String.format("商品[%s]库存可用量不足，单据号：%s", detail.getCmaterialvid().getName(), whsTransBillHeaderVo.getVbillcode()));
            } else if (resultType == InventoryCheck.NOT_ALLOWED.ordinal()) {
                throw new InventoryException(String.format("商品[%s]不支持在此单据类型下使用，单据号：%s", detail.getCmaterialvid().getName(), whsTransBillHeaderVo.getVbillcode()));
            }
        }
    }

    /**
     * 更新单据状态
     *
     * @param cspecialhid 表头主键
     * @param status      状态码
     * @param loginUser   登录用户
     */
    private void updateBillState(String cspecialhid, String status, LoginUser loginUser) {
        whstransbillMapper.updateBillState(cspecialhid, status, loginUser.getUsername(), DataProcessUtils.getLocalDate());
//        log.info("单据状态更新成功，单据号：{}，状态：{}", cspecialhid, status);
    }
}
